// Package validator 验证器
package validator

import (
	"errors"
	"reflect"
	"strings"

	"github.com/gin-gonic/gin/binding"
	"github.com/go-playground/validator/v10"

	"github.com/go-playground/locales/en"
	"github.com/go-playground/locales/zh"
	ut "github.com/go-playground/universal-translator"
	zhTrans "github.com/go-playground/validator/v10/translations/zh"
)

// GinValidator gin验证器
type GinValidator struct {
	validate   *validator.Validate
	translator ut.Translator
}

// NewGinValidator 实例化gin验证器
func NewGinValidator() (*GinValidator, error) {
	var (
		validate   *validator.Validate
		translator ut.Translator
		ok         bool
	)

	if validate, ok = binding.Validator.Engine().(*validator.Validate); !ok {
		return nil, errors.New("gin为实现验证器")
	}

	uniTranslator := ut.New(en.New(), zh.New())
	if translator, ok = uniTranslator.GetTranslator("zh"); !ok {
		return nil, errors.New("获取翻译器出错")
	}

	if err := zhTrans.RegisterDefaultTranslations(validate, translator); err != nil {
		return nil, err
	}

	r := &GinValidator{
		validate:   validate,
		translator: translator,
	}

	//初始化字段tag
	_ = r.registerTagName()

	//注册全局验证规则
	err := r.registerGlobalRules(commonRules)
	if err != nil {
		return nil, err
	}

	return r, nil
}

// GetTranslator 获取翻译器
func (r *GinValidator) GetTranslator() ut.Translator {
	return r.translator
}

// GetValidate 获取验证器
func (r *GinValidator) GetValidate() *validator.Validate {
	return r.validate
}

// RegisterValidate 注册验证规则
func (r *GinValidator) RegisterValidate(
	tag string,
	validatorFunc validator.Func,
	transRegFunc validator.RegisterTranslationsFunc,
	translationFunc validator.TranslationFunc) error {
	if r.validate == nil || r.translator == nil {
		return errors.New("请先初始化验证器和翻译器")
	}
	if validatorFunc != nil {
		err := r.validate.RegisterValidation(tag, validatorFunc)
		if err != nil {
			return err
		}
	}

	if transRegFunc != nil && translationFunc != nil {
		err := r.validate.RegisterTranslation(tag, r.translator, transRegFunc, translationFunc)
		if err != nil {
			return err
		}
	}

	return nil
}

// 注册全局验证规则
func (r *GinValidator) registerGlobalRules(commonRules map[string]ValidateRule) error {
	for key, item := range commonRules {
		err := r.RegisterValidate(key, item.ValidateFunc, item.RegisterFunc, item.TranslationFunc)
		if err != nil {
			return err
		}
	}
	return nil
}

// 注册tag名称
func (r *GinValidator) registerTagName() error {
	if r.validate == nil {
		return errors.New("请先初始化验证器")
	}

	r.validate.RegisterTagNameFunc(func(field reflect.StructField) string {
		name := strings.SplitN(field.Tag.Get("comment"), ",", 2)
		if len(name) > 0 {
			return name[0]
		}
		return ""
	})

	return nil
}
